/*
参考代码：https://blog.csdn.net/caijiwyj/article/details/90314312
*/
#include "driver_usart.h"
#include "project.h"
//namespace mower_driver {


/***********************************************
 * @author: tianxiaogua
 * @date:   23/8
 * @brief:  增加参数配置
 * @var:    void
 * @return: None
 ***********************************************/
SerialDriver::SerialDriver(const char *_path, speed_t _speed)
{
  struct termios term;
  serial_path = _path;
  // O_RDONLY：以只读方式打开文件  O_WRONLY：以只写方式打开文件 O_RDWR：以读写方式打开文件
  fd = open(_path, O_RDWR | O_NOCTTY | O_NDELAY);
  if (fd == -1)
  {
    GUA_LOGE("Err INfo: open {} error!", _path);
    SerialDriver_state = SERIALDRIVER_ERROR;
  }

  if(tcgetattr(fd, &term) != 0) // 用于获取与终端相关的参数
  {
      GUA_LOGE("tcgetattr error");
      SerialDriver_state = SERIALDRIVER_ERROR;
  }

  cfmakeraw(&term); // 使得串口工作于RAW模式,为原始模式

  /* 计算得到具体的参数配置 */
  term.c_cflag &= ~CSTOPB; // 1位停止位
	//term.c_cflag |= CSTOPB; // 2位停止位

  term.c_cflag &= ~PARENB; // 无校验
	//term.c_cflag |= PARENB; // 开校验

	//term.c_cflag &= ~PARODD; // 表示奇校验
	//term.c_cflag |= PARODD; // 无校验

	term.c_cflag &= ~CSIZE; // 去掉数据位屏蔽
	term.c_cflag |= CS8; // 8位数据位 可选CS7

  /* set timeout in deciseconds for noncanonical read */
  term.c_cc[VTIME] = 0;
  /* set minimum number of bytes to read */
  term.c_cc[VMIN] = 0;

  /* 清空缓冲区 */
  tcflush(fd ,TCIFLUSH);/* tcflush清空终端未完成的输入/输出请求及数据；TCIFLUSH表示清空正收到的数据，且不读取出来 */

	/* 常见的波特率：
	B115200
	B9600
	*/
  if(cfsetspeed(&term, _speed) < 0) // 配置串口波特率
  {
      GUA_LOGE("cfsetspeed error");
      SerialDriver_state = SERIALDRIVER_ERROR;
  }

	/*
	TCSANOW - 立即生效
	TCSADRAIN - 输入输出完成后生效
	TCSAFLUSH - 刷新缓冲区后生效
	前面已经完成了对 struct termios 结构体各个成员进行配置，但是配置还未生效，需要将配置参数
	写入到串口，使其生效。通过 tcsetattr()函数将配置参数写入到硬件设备。
	*/
  if(tcsetattr(fd, TCSADRAIN, &term) < 0) // 写入配置
	{
    GUA_LOGE("tcsetattr error");
    SerialDriver_state = SERIALDRIVER_ERROR;
  }

    /* 设置低延迟模式 */
	struct serial_struct serial_info;

	ioctl(fd, TIOCGSERIAL, &serial_info);

  serial_info.flags |= ASYNC_LOW_LATENCY;

  ioctl(fd, TIOCSSERIAL, &serial_info);
  SerialDriver_state = SERIALDRIVER_OPEN;
  //close(fd);
}

SerialDriver::~SerialDriver()
{
  close(fd);
}


/***********************************************
 * @author: tianxiaogua
 * @date:   23/8
 * @brief:  对各个驱动进程下面的各个驱动线程做初始化管理
 * @var:    void
 * @return: None
 ***********************************************/
uint32_t recv_data_len = 0;
int SerialDriver::ReadBytesBlock(uint8_t *rev_buf, int rev_len, int time)
{
  struct pollfd fds[1];
  uint8_t temp_recv_buf[32] = {0};
  uint32_t tepm_len = 0;
  if(fd < 0) {
      printf("error\n");
  }
  recv_data_len = 0;
  fds[0].fd = fd;
  fds[0].events = POLLIN; // 使用阻塞中断 监听事件
  int recv_times = 0;
  while(1){
    int poll_return = poll(fds, 1, 20); // 单位毫秒 -1 永远不会超时 1毫秒返回一次
    if (poll_return == 0) {
        //printf(".\n");
        if(recv_data_len != 0){ // 没有任何事件发生
          //recv_data_len = 0;
          recv_times = 0;
          tepm_len = recv_data_len;
          recv_data_len = 0;
          return tepm_len;
        }
        recv_data_len = 0;
        recv_times = 0;
        return RECV_DONE;
    }
    else if (poll_return < 0) {
        int error_num = errno;
        error_num = poll_return;
        switch (error_num) {
            case EINTR:
                return REV_NULL;
            default:
                printf("Error polling serial port%s",serial_path.c_str());
                return REV_ERROR;
        }
    }
    memset(temp_recv_buf, 0x00, 32);
    int result = read(fd, temp_recv_buf, 32); // result 读取到的数据长度
    recv_data_len = recv_data_len+result;
    //printf("ReadBytesBlock result: %d  recv_data_len: %d\r\n", result, recv_data_len);
    printf("usart recv:%d\n", recv_data_len);
    for(int i=0; i<32;i++){
      rev_buf[i+recv_times*32] = temp_recv_buf[i];
      printf("%x ",rev_buf[i+recv_times*32]);
    }printf("\n");
    recv_times++;
  }
}

uint8_t arev_buf[512];
///考虑串口读超时处理
int SerialDriver::ReadBuf(Usart_Buf & usartBuf, int timeout)
{
  struct pollfd fds[1];
  uint8_t temp_recv_buf[32] = {0};
  uint32_t tepm_len = 0;
  if(fd < 0) {
      printf("error\n");
  }
  recv_data_len = 0;
  fds[0].fd = fd;
  fds[0].events = POLLIN; // 使用阻塞中断 监听事件
  int recv_times = 0;
  while(1){
    int poll_return = poll(fds, 1, 100); // 单位毫秒 -1 永远不会超时 1毫秒返回一次
    if (poll_return == 0) { // 如果超时了
        //printf(".\n");
        if(recv_data_len != 0){ // 没有任何事件发生
          //recv_data_len = 0;
          recv_times = 0;
          tepm_len = recv_data_len;
          recv_data_len = 0;
          //printf("usart recv:%d\n", tepm_len);
          // for(int i=0; i<tepm_len;i++){
          //   printf("%x ",arev_buf[i]);
          //   //rev_buf[i] = arev_buf[i];
          //   usartBuf.rev_buf[i] = arev_buf[i];
          // }printf("\n");
          return tepm_len;
        }
        else {
          return REV_TIOMEOUT;
        }
    }
    else if (poll_return < 0) {
        int error_num = errno;
        error_num = poll_return;
        switch (error_num) {
            case EINTR:
                return REV_NULL;
            default:
                printf("Error polling serial port:%s",serial_path.c_str());
                return REV_ERROR;
        }
    }
    memset(temp_recv_buf, 0x00, 32);
    int result = read(fd, temp_recv_buf, 32); // result 读取到的数据长度
    recv_data_len = recv_data_len+result;
    //printf("ReadBytesBlock result: %d  recv_data_len: %d\r\n", result, recv_data_len);
    //printf("usart recv:%d\n", recv_data_len);
    for(int i=0; i<32;i++){
      arev_buf[i+recv_times*32] = temp_recv_buf[i];
      printf("%x ",arev_buf[i+recv_times*32]);
    }printf("\n");
    recv_times++;
  }
}



int32_t SerialDriver::ReadBytes(std::vector<uint8_t>& output, size_t max_bytes, int32_t timeout)
{
    if (fd < 0) {
        GUA_LOGE("Device not open!,path:{}", serial_path.c_str());
        usleep(1000000);
        return REV_ERROR;
    }

    struct pollfd fds[1];
    fds[0].fd = fd;
    fds[0].events = POLLIN;

    int poll_return = poll(fds, 1, timeout);
    if (poll_return == 0) {
        // AINFO_F(" Timed out while waiting for data");
        return REV_TIOMEOUT;
    } else if (poll_return < 0) {
        close(fd);
        fd = -1;
        int error_num = errno;
        switch (error_num) {
            case EINTR:
                return REV_NULL;
            default:
                GUA_LOGE(" Error polling serial port");
                return REV_ERROR;
        }
    }

    size_t to_read = max_bytes;
    if (to_read <= 0) {
        int bytes;
        ioctl(fd, FIONREAD, &bytes); // 使用ioctrl读取出当前的串口数据长度
        if (bytes < 0) {
            GUA_LOGE(" Error getting number of available bytes from serial port");
            return REV_ERROR;
        }
        to_read = static_cast<size_t>(bytes);
    }

    size_t output_size = output.size(); // 获取当前vector的大小
    output.resize(output_size + to_read); // 把当前容器的大小扩到的原理的基础上增加读取到的串口数据长度的大小

    int result = read(fd, output.data() + output_size, to_read); // 串口读取到的数据存放在vector的最后一个数据的地址后面

    if (result > 0) {
        output.resize(output_size + result);
    } else {
        output.resize(output_size);
    }

    if (result > 0) {
        return RECV_DONE; // 正常接收完成
    } else if (result == 0) {
        return REV_ERROR;
    } else {
        int error_num = errno;
        switch (error_num) {
            case EINTR:
                return REV_NULL;
                break;
            default:
                GUA_LOGE(" Error reading serial port\n");
                return REV_ERROR;
        }
    }
}

int SerialDriver::Write(const std::vector<uint8_t>& input)
{
  if (fd < 0) {
        GUA_LOGE("Device not open!,path:{}", serial_path.c_str());
        return REV_ERROR;
  }
  return write(fd, input.data(), input.size());
}

int SerialDriver::Write(const std::string& _input)
{
  if (fd < 0) {
        GUA_LOGE("Device not open!,path:{}", serial_path.c_str());
        return REV_ERROR;
  }
  return write(fd, _input.data(), _input.size());
}

int SerialDriver::Write(uint8_t *pinput, uint32_t pinput_size)
{
  if (fd < 0) {
        GUA_LOGE("Device not open!,path:{}", serial_path.c_str());
        return REV_ERROR;
  }
  return write(fd, pinput, pinput_size);
}

 // namespace smiles_driver

